import Cesium, { Cartesian3, Event } from '../Ces/Cesium'

class WeViewExtentEvent {
    lastChangePosition: Cartesian3
    lastChangeFrameNumber: number

    debugRectangePrimitive
    scene
    rectangleScratch
    dirty: boolean = false
    _showDebug: boolean = false
    _extentChangedEvent: Event
    _removeEventSubscription
    tiles
    _enable
    appearance
    onExtentChanged
    colorScratch
    constructor(scene) {
        this.scene = scene
        this.lastChangePosition = new Cesium.Cartesian3()
        this.rectangleScratch = new Cesium.Rectangle()
        this.lastChangeFrameNumber = 0
        this._showDebug = false
        this._extentChangedEvent = new Cesium.Event()
        this._removeEventSubscription = this._extentChangedEvent.addEventListener(
            this._onExtentChanged,
            this,
        )
        this.tiles = {}
        this._enable = true
        this.appearance = undefined
        this.debugRectangePrimitive = undefined
    }

    get enable() {
        return this._enable
    }
    set enable(value) {
        this._enable = value
    }

    get showDebug() {
        return this._showDebug
    }
    set showDebug(value) {
        this._showDebug = value
    }

    get viewExtent() {
        return this.rectangleScratch
    }

    get extentChangedEvent() {
        return this._extentChangedEvent
    }

    _onExtentChanged(_sender, _message, _extent) {
        if (this.onExtentChanged) {
            this.onExtentChanged(_sender, _message, _extent)
        }
    }

    update(frameState) {
        if (!frameState.passes.render || !this._enable) {
            return
        }

        const { scene, tiles, } = this

        let maxLevel = 0

        Object.values(tiles).forEach((e: any) => {
            e.west = e.south = e.east = e.north = 0
        })

        scene.globe._surface.forEachRenderedTile((tile) => {
            tile.data.imagery.forEach((element) => {
                const imagery = element.readyImagery

                if (imagery) {
                    const { level } = imagery
                    if (!tiles[level]) {
                        tiles[level] = imagery.rectangle.clone(new Cesium.Rectangle())
                    }
                    const rectangle = tiles[level]
                    if (rectangle.east === rectangle.west) {
                        imagery.rectangle.clone(rectangle)
                    } else {
                        Cesium.Rectangle.union(rectangle, imagery.rectangle, rectangle)
                    }
                    if (level > maxLevel) maxLevel = level
                }
            })
        })

        let rectangle = tiles[maxLevel]

        for (let r = 1; r < 3; r++) {
            const lRectange = tiles[maxLevel - r]
            if (!lRectange || lRectange.east === lRectange.west) {
                break
            }
            Cesium.Rectangle.union(rectangle, lRectange, rectangle)
        }

        if (rectangle && !Cesium.Rectangle.equals(rectangle, this.rectangleScratch, Cesium.Math.EPSILON1)) {
            rectangle.clone(this.rectangleScratch)
            this.dirty = true
        }
        else if (this.dirty && (frameState.frameNumber - this.lastChangeFrameNumber > 0)) {
            this.dirty = false
            this.lastChangeFrameNumber = frameState.frameNumber
            if (this._showDebug) {
                // log out
                console.log(`${Cesium.Math.toDegrees(this.rectangleScratch.west)},${Cesium.Math.toDegrees(this.rectangleScratch.south)},${Cesium.Math.toDegrees(this.rectangleScratch.east)},${Cesium.Math.toDegrees(this.rectangleScratch.north)}`)
                if (!Cesium.defined(this.appearance)) {
                    this.appearance = new Cesium.EllipsoidSurfaceAppearance({
                        material: Cesium.Material.fromType('Color')
                    })
                }
                this.debugRectangePrimitive = this.debugRectangePrimitive && this.debugRectangePrimitive.destroy()
                var rectangleInstance = new Cesium.GeometryInstance({
                    geometry: new Cesium.RectangleGeometry({
                        rectangle: this.rectangleScratch,
                        vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
                    })
                })

                if (!this.colorScratch) this.colorScratch = new Cesium.Color()
                if (this.rectangleScratch.width === Cesium.Math.TWO_PI) {
                    this.appearance.material.uniforms.color = Cesium.Color.RED.withAlpha(0.5, this.colorScratch)
                } else if (this.rectangleScratch.width > Cesium.Math.PI) {
                    this.appearance.material.uniforms.color = Cesium.Color.YELLOW.withAlpha(0.5, this.colorScratch)
                } else {
                    this.appearance.material.uniforms.color = Cesium.Color.WHITE.withAlpha(0.5, this.colorScratch)
                }

                this.debugRectangePrimitive = new Cesium.Primitive({
                    geometryInstances: [rectangleInstance],
                    appearance: this.appearance
                })
            }
            this._extentChangedEvent.raiseEvent(this, 'onExtentChanged', this.rectangleScratch)
        }

        if (this._showDebug && this.debugRectangePrimitive) {
            this.debugRectangePrimitive.update(frameState)
        }
    }

    destroy() {
        this.debugRectangePrimitive = this.debugRectangePrimitive && this.debugRectangePrimitive.destroy()
        this._removeEventSubscription()
        return Cesium.destroyObject(this)
    }

    isDestroyed() {
        return false
    }
}


export default WeViewExtentEvent
